#pragma once

#include <iostream>
#include <stdexcept>


// do/while macro trick
inline void func1()
{
    std::cout << "func1" << std::endl;
}

inline void func2()
{
    std::cout << "func2" << std::endl;
}

// not work
#define MACRO1 \
    { \
        func1(); \
        func2(); \
    }

// work
#define MACRO2 \
    do { \
        func1(); \
        func2(); \
    } while(false)

//    if(true)
//        MACRO1; // not work - because else without previous if
//    else
//        std::cout << "ole";

//    if(true)
//        MACRO2; // this work - do/while trick
//    else
//        std::cout << "ole";


// у нас активно пользуют макросы для эксепшенов, чтобы не загромождать код throw/catch
// STINGRAY_TRY_DO("сообщение об ошибке", имя метода );
// ну соотвестенно, если из вызываемого метода вылетит эксепшон, то благодаря макросу его поймают и напишут сообщение об ошибке
// ещё есть макрос который проверяет условие, и если оно не выполняется, кидает экспешон
// что-то типа TOOLKIT_CHECK(условие, "сообщение об ошибке")
// этими штуками удобно пользоваться, они не загромождают код

// see do/while trick above
#define STINGRAY_TRY_DO(ErrorMessage_, ...) \
    do { \
    try { __VA_ARGS__; } \
    catch (const std::exception& ex) { s_logger.Warning() << (ErrorMessage_) << ":\n" << stingray::diagnostic_information(ex); } \
    } while (0)



// ещё  у нас есть макрос для создания классов эксепшенов
class Exception
        : public std::runtime_error
{
public:
    Exception(const std::string& message)
        : std::runtime_error(message)
    {
    }

    virtual ~Exception() throw()
    {
    }
};

// типа такого
// и от него наследуются классы типа ArgumentException NullPointerException InvalidCastException ну и так далее
// для них сразу определяешь сообщение, и потом в нужной ситуайии просто кидаешь нужный тип эксепшена, чтобы каждый раз одно и тоже не писать
// но это ещё цветочки=)
